//=============================================================================//
//  ___  ___   _   _   _    __   _   ___ ___ __ __
// |_ _|| __| / \ | \_/ |  / _| / \ | o \ o \\ V /
//  | | | _| | o || \_/ | ( |_n| o ||   /   / \ / 
//  |_| |___||_n_||_| |_|  \__/|_n_||_|\\_|\\ |_|  2006
//										 
//=============================================================================//
/*
Following mess is a hack for getting ATL working under VCEE
*/
#define _ATL_APARTMENT_THREADED
#include <atlbase.h>
extern CComModule _Module;
#include <atlcom.h>

namespace ATL {
    void * __stdcall __AllocStdCallThunk()
    {
        return HeapAlloc(GetProcessHeap(),
            0, sizeof(_stdcallthunk));
    }

    void __stdcall __FreeStdCallThunk(void *p)
    {
        HeapFree(GetProcessHeap(), 0, p);
    }
}
/*
End of mess
*/

#include <locale>
#include <windows.h>
#include <sapi.h>
#include "common/GMLuaModule.h"

ISpVoice* Voice = NULL;
USHORT DefaultVolume;
long DefaultRate;

GMOD_MODULE( Init, Shutdown );

//gspeak.Say(msg, volume (0~100), rate (-10~10))
typedef struct
{
	wchar_t* msg;
	USHORT volume;
	short rate;
	int args;
} SAYINFO;

static void Speak(SAYINFO* info);

LUA_FUNCTION( Say )
{
	//form message
	const char* msg = g_Lua->GetString(1);
	size_t len = strlen(msg);

	SAYINFO* info = new SAYINFO;
	std::locale loc;

	info->msg = new wchar_t[len];
	
	std::use_facet< std::ctype<wchar_t> >(loc).widen ( msg, msg+len, info->msg );
	
	info->args = g_Lua->Top();
	
	//volume and rate optional arguments
	if(info->args > 1)
	{
		info->volume = g_Lua->GetInteger(2);

		if(info->args > 2)
			info->rate = g_Lua->GetInteger(3);
	}
	
	CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&Speak, info, 0, NULL);
	return 0;
}

//thread entry
static void Speak(SAYINFO* info)
{
	if(info->args > 1)
	{
		Voice->SetVolume(info->volume);

		if(info->args > 2)
			Voice->SetRate(info->rate);
	}

	Voice->Speak(info->msg, 0, NULL);

	delete info->msg, info;

	if(info->args > 1)
	{
		Voice->SetVolume(DefaultVolume);

		if(info->args > 2)
			Voice->SetRate(DefaultRate);
	}
}

int Init( void )
{
	if (FAILED(::CoInitialize(NULL)))
        return 1;

	HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&Voice);
    if( !SUCCEEDED( hr ) )
        return 1;

	Voice->GetVolume(&DefaultVolume);
	Voice->GetRate(&DefaultRate);
	
	g_Lua->NewGlobalTable( "gspeak" );
	ILuaObject* table = g_Lua->GetGlobal( "gspeak" );
		table->SetMember( "Say", Say );
	SAFE_UNREF( table );
	return 0;
}

//Shut down SAPI
int Shutdown( void )
{
	Voice->Release();
    Voice = NULL;

	::CoUninitialize();
	return 0;
}

